﻿using Jian.Vubackup.MySql.Tool;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Threading;

namespace Jian.Vubackup.MySql
{
    class Program
    {
        static Process mproc = null;
        static ILog log = new LogWeb();
        static void Main(string[] args)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            WriteInfo("****************************************************************************");
            WriteInfo("*                               备份任务开始                               *");
            WriteInfo("*                                 **jian**                                 *");
            WriteInfo("****************************************************************************");

            //备份数据库
            BackUpDataBase();

            //备份文件夹
            BackUpFolder();


            WriteInfo("****************************************************************************");
            WriteInfo("*                               备份任务完成                               *");
            WriteInfo("*                              **5秒后关闭**                               *");
            WriteInfo("****************************************************************************");
            WriteInfo("5");
            Thread.Sleep(1000);
            WriteInfo("4");
            Thread.Sleep(1000);
            WriteInfo("3");
            Thread.Sleep(1000);
            WriteInfo("2");
            Thread.Sleep(1000);
            WriteInfo("1");
            Thread.Sleep(1000);
            WriteInfo("系统关闭");

        }

        static void mproc_Exited(object sender, EventArgs e)
        {
            WriteInfo("Exited");
        }



        static void mproc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {

            string value = e.Data;
            if (value != null)
            {
                if (!string.IsNullOrWhiteSpace(value))
                {
                    WriteInfo(value);
                }
                if (value.IndexOf("Disconnecting from localhost") >= 0)
                {
                    mproc.Kill();
                    //Environment.Exit(0);

                }
            }
        }
        static void mproc_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(e.Data))
            {
                WriteInfo(e.Data);
            }

        }

        #region 写日志
        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="content"></param>
        private static void WriteInfo(string content)
        {
            Console.WriteLine(content);
            log.WriteInfo(content);
        }
        #endregion

        #region 获取配置文件信息
        /// <summary>
        /// 获取配置文件信息
        /// </summary>
        /// <returns></returns>
        private static BackupModel GetConfig()
        {
            ConfigManager manager = new ConfigManager("config.json");
            BackupModel model = manager.GetConfig<BackupModel>("Backup");
            return model;
        }
        #endregion

        #region 清除老的数据库备份文件
        /// <summary>
        /// 清除老的数据库备份文件
        /// </summary>
        /// <param name="config"></param>
        private static void ClearOldDb(BackupModel config)
        {
            Group group = new Group();

            DirectoryInfo dirInfo = new DirectoryInfo(config.BackupDir);
            if (dirInfo != null && dirInfo.Exists)
            {
                FileInfo[] fileList = dirInfo.GetFiles();
                if (fileList != null && fileList.Length > 0)
                {
                    foreach (FileInfo file in fileList)
                    {
                        if (file.Exists)
                        {
                            if (file.Extension == ".mysqlbak")
                            {
                                string name = Path.GetFileNameWithoutExtension(file.Name);
                                string[] array = name.Split('@');
                                if (array != null && array.Length > 0)
                                {
                                    FileInfoItem fileItem = new FileInfoItem();
                                    fileItem.DbName = array[0];
                                    fileItem.Time = JTool.GetNoNullLong(array[1]);
                                    fileItem.File = file;
                                    group.AddFileItem(fileItem);
                                }
                            }

                        }
                    }
                }
            }

            group.Clear();
        }
        #endregion

        #region 备份数据库
        /// <summary>
        /// 备份数据库
        /// </summary>
        private static void BackUpDataBase()
        {
            string app = "mysqldump";
            if (PlatformHelper.IsLinux)
            {
                app = "/usr/bin/mysqldump";
            }

            BackupModel config = GetConfig();


            ClearOldDb(config);



            if (config != null && config.Db != null && config.Db.Length > 0)
            {
                string toDir = config.BackupDir;
                if (!Directory.Exists(toDir))
                {
                    Directory.CreateDirectory(toDir);
                }

                foreach (string dbname in config.Db)
                {
                    WriteInfo($"开始备份数据库{dbname}");
                    string param = $"-quick --host={config.Ip} --default-character-set=utf8 --lock-tables --verbose  --force --port=3306 --user={config.User} --password={config.psd} {dbname} -r {config.BackupDir}/{dbname.ToLower()}@{JTool.DatetimeToTimeStampJavaScript(DateTime.Now)}.mysqlbak";

                    ProcessStartInfo startinfo = new ProcessStartInfo();
                    //运行程序名
                    startinfo.FileName = app;
                    //设置工作目录
                    startinfo.WorkingDirectory = AppContext.BaseDirectory;
                    //关闭Shell
                    startinfo.UseShellExecute = false;
                    //重定向标准输入
                    startinfo.RedirectStandardInput = true;
                    //重定向标准输出
                    startinfo.RedirectStandardOutput = true;
                    //重定向错误输出
                    startinfo.RedirectStandardError = true;
                    //不显示窗口
                    startinfo.CreateNoWindow = true;
                    startinfo.Arguments = param;

                    mproc = new Process();
                    mproc.OutputDataReceived -= new DataReceivedEventHandler(mproc_OutputDataReceived);
                    mproc.OutputDataReceived += new DataReceivedEventHandler(mproc_OutputDataReceived);
                    mproc.ErrorDataReceived -= new DataReceivedEventHandler(mproc_ErrorDataReceived);
                    mproc.ErrorDataReceived += new DataReceivedEventHandler(mproc_ErrorDataReceived);
                    mproc.Exited -= new EventHandler(mproc_Exited);
                    mproc.Exited += new EventHandler(mproc_Exited);

                    mproc.EnableRaisingEvents = true;

                    mproc.StartInfo = startinfo;

                    //执行ver命令
                    mproc.Start();

                    mproc.BeginOutputReadLine();
                    mproc.BeginErrorReadLine();

                    mproc.WaitForExit();
                    WriteInfo($"结束备份数据库{dbname}");
                }

            }
        }
        #endregion


        #region 备份文件夹
        /// <summary>
        /// 备份文件夹
        /// </summary>
        private static void BackUpFolder()
        {
            BackupModel config = GetConfig();
            if (config != null && config.Folders != null && config.Folders.Length > 0)
            {
                //清除老的备份文件夹
                ClearOldFolderBack(config);

                //备份到文件夹
                string toDir = config.BackupDir;
                if (!Directory.Exists(toDir))
                {
                    Directory.CreateDirectory(toDir);
                }

                //临时文件夹
                string toDirTemp = Path.Combine(toDir, "temp");
                if (Directory.Exists(toDirTemp))
                {
                    bool isDelete = true;
                    while (isDelete)
                    {
                        try
                        {
                            DeleteFolder(toDirTemp);
                            isDelete = false;
                        }
                        catch (Exception ex)
                        {
                            log.WriteException(ex);
                            Console.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
                            isDelete = true;
                        }
                    }
                }
                if (!Directory.Exists(toDirTemp))
                {
                    Directory.CreateDirectory(toDirTemp);
                }

                foreach (string folderDir in config.Folders)
                {
                    DirectoryInfo dir = new DirectoryInfo(folderDir);
                    if (dir.Exists)
                    {
                        //备份到临时文件夹
                        Console.WriteLine($"备份临时文件夹[{dir.Name}]");
                        CopyFolder(folderDir, toDirTemp);
                        string sourceDir = Path.Combine(toDirTemp, dir.Name);
                        string toZipFile = Path.Combine(toDir, $"folder@{dir.Name}@{JTool.DatetimeToTimeStampJavaScript(DateTime.Now)}.zip");
                        //压缩文件夹
                        Console.WriteLine($"压缩文件夹[{dir.Name}]");
                        ZipFile.CreateFromDirectory(sourceDir, toZipFile, CompressionLevel.Optimal, true);
                    }
                }

                //if (Directory.Exists(toDirTemp))
                //{
                //    Console.WriteLine("5");
                //    Thread.Sleep(1000);
                //    Console.WriteLine("4");
                //    Thread.Sleep(1000);
                //    Console.WriteLine("3");
                //    Thread.Sleep(1000);
                //    Console.WriteLine("2");
                //    Thread.Sleep(1000);
                //    Console.WriteLine("1");
                //    Thread.Sleep(1000);
                //    DeleteFolder(toDirTemp);
                //}
            }
        }
        #endregion

        /// <summary>
        /// 备份文件夹
        /// </summary>
        /// <param name="sourceFolder">原始文件夹</param>
        /// <param name="toDir">备份到的目标目录</param>
        private static void CopyFolder(string sourceFolder, string toDir)
        {
            if (!Directory.Exists(sourceFolder))
            {
                throw new Exception("原始文件夹不存在");
            }

            if (!Directory.Exists(toDir))
            {
                throw new Exception("备份到的目标目录不存在");
            }

            DirectoryInfo sourceDir = new DirectoryInfo(sourceFolder);

            string toFolder = Path.Combine(toDir, sourceDir.Name);
            if (!Directory.Exists(toFolder))
            {
                Directory.CreateDirectory(toFolder);
            }

            // 获取源文件夹下的文件
            FileInfo[] fileList = sourceDir.GetFiles();
            if (fileList != null && fileList.Length > 0)
            {
                foreach (FileInfo file in fileList)
                {
                    Console.WriteLine($"备份临时文件{file.FullName}");
                    string toFileName = Path.Combine(toFolder, file.Name);
                    file.CopyTo(toFileName);
                }
            }
            // 获取源文件夹下的文件夹
            DirectoryInfo[] dirList = sourceDir.GetDirectories();
            if (dirList != null && dirList.Length > 0)
            {
                foreach (DirectoryInfo item in dirList)
                {
                    Console.WriteLine($"备份临时文件夹{item.FullName}");
                    CopyFolder(item.FullName, toFolder);
                }
            }
        }

        /// <summary>
        /// 删除目录
        /// </summary>
        /// <param name="dir"></param>
        private static void DeleteFolder(string dir)
        {
            if (Directory.Exists(dir))
            {
                Console.WriteLine($"删除临时文件夹{dir}");
                DirectoryInfo directoryInfo = new DirectoryInfo(dir);
                // 获取源文件夹下的文件
                FileInfo[] fileList = directoryInfo.GetFiles();
                if (fileList != null && fileList.Length > 0)
                {
                    foreach (FileInfo file in fileList)
                    {
                        file.Delete();
                    }
                }
                // 获取源文件夹下的文件夹
                DirectoryInfo[] dirList = directoryInfo.GetDirectories();
                if (dirList != null && dirList.Length > 0)
                {
                    foreach (DirectoryInfo item in dirList)
                    {
                        DeleteFolder(item.FullName);
                    }
                }
                Directory.Delete(dir, true);
            }
        }


        #region 清除老的文件夹备份文件
        /// <summary>
        /// 清除老的文件夹备份文件
        /// </summary>
        /// <param name="config"></param>
        private static void ClearOldFolderBack(BackupModel config)
        {
            Group group = new Group();

            DirectoryInfo dirInfo = new DirectoryInfo(config.BackupDir);
            if (dirInfo != null && dirInfo.Exists)
            {
                FileInfo[] fileList = dirInfo.GetFiles();
                if (fileList != null && fileList.Length > 0)
                {
                    foreach (FileInfo file in fileList)
                    {
                        if (file.Exists)
                        {
                            if (file.Extension == ".zip")
                            {
                                string name = Path.GetFileNameWithoutExtension(file.Name);
                                string[] array = name.Split('@');
                                if (array != null && array.Length > 0)
                                {
                                    FileInfoItem fileItem = new FileInfoItem();
                                    fileItem.DbName = array[1];
                                    fileItem.Time = JTool.GetNoNullLong(array[2]);
                                    fileItem.File = file;
                                    group.AddFileItem(fileItem);
                                }
                            }

                        }
                    }
                }
            }

            group.Clear();
        }
        #endregion
    }
}
